package com.fs.alert.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fs.alert.domain.po.Alert;
import com.fs.alert.domain.po.AlertRobot;
import com.fs.alert.domain.vo.*;
import com.fs.alert.service.IDetectionService;
import com.fs.api.domain.vo.DetectionVO;
import com.fs.api.enumeration.AlertStatus;
import com.fs.api.enumeration.AlertType;
import com.fs.alert.mapper.AlertMapper;
import com.fs.alert.mapper.AlertRobotMapper;
import com.fs.alert.service.IAlertService;
import com.fs.api.client.RobotClient;
import com.fs.api.domain.vo.AlertDetailVO;
import com.fs.api.domain.vo.RobotVO;
import com.fs.common.domain.PageVO;
import com.fs.common.domain.Result;
import com.fs.common.exception.BusinessException;
import com.fs.common.utils.BeanUtils;
import com.fs.common.utils.CollUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.WeekFields;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

import static com.fs.api.enumeration.EmergencyLevel.URGENT;
import static com.fs.common.enumeration.BusinessExceptionEnum.ALERT_NOT_FOUND;

@Slf4j
@Service
@RequiredArgsConstructor
public class AlertServiceImpl extends ServiceImpl<AlertMapper, Alert> implements IAlertService {
    private final AlertMapper alertMapper;
    private final AlertRobotMapper alertRobotMapper;
    private final IDetectionService detectionService;

    private final RobotClient robotClient;

    @Override
    public PageVO<AlertListVO> getAlerts(Integer current, Integer size, AlertType alertType, AlertStatus status,
                                         String alertNo, LocalDateTime startTime, LocalDateTime endTime) {
        Page<Alert> page = new Page<>(current, size);
        LambdaQueryWrapper<Alert> wrapper = Wrappers.<Alert>lambdaQuery();

        // 添加警情编号筛选条件，使用like进行模糊查询
        if (StringUtils.hasText(alertNo)) {
            wrapper.like(Alert::getAlertNo, alertNo);
        }

        // 修改判断条件，直接判断枚举是否为null
        if (alertType != null) {
            wrapper.eq(Alert::getAlertType, alertType);
        }
        if (status != null) {
            wrapper.eq(Alert::getStatus, status);
        }

        // 添加时间范围筛选
        if (startTime != null) {
            wrapper.ge(Alert::getAlertTime, startTime);
        }
        if (endTime != null) {
            wrapper.le(Alert::getAlertTime, endTime);
        }

        // 添加排序，按创建时间倒序
        wrapper.orderByDesc(Alert::getCreatedTime);

        // 执行分页查询
        Page<Alert> alertPage = alertMapper.selectPage(page, wrapper);

        List<AlertListVO> voList = alertPage.getRecords().stream()
                .map(alert -> {
                    AlertListVO alertListVO = new AlertListVO();
                    BeanUtils.copyProperties(alert, alertListVO);
                    return alertListVO;
                }).collect(Collectors.toList());

        // 将查询结果转换为PageVO对象
        Page<AlertListVO> voPage = new Page<>(alertPage.getCurrent(), alertPage.getSize());
        voPage.setRecords(voList);
        voPage.setTotal(alertPage.getTotal());
        voPage.setPages(alertPage.getPages());

        // 返回结果
        return PageVO.of(voPage);
    }

    @Override
    public AlertDetailVO getAlertDetail(Long id, boolean withOthers) {
        // 1. 查询警情基本信息
        Alert alert = alertMapper.selectById(id);
        if (alert == null) {
            throw new BusinessException(ALERT_NOT_FOUND);
        }

        AlertDetailVO detailVO = new AlertDetailVO();
        BeanUtils.copyProperties(alert, detailVO);

        // AlertDetailVO中的createdTime需要从Alert的alertTime映射
        detailVO.setCreatedTime(alert.getAlertTime());
        // 确保状态一致性，避免VO中重复的alertStatus字段
        detailVO.setAlertStatus(alert.getStatus());

        if (withOthers) {
            // 5.查询关联的机器人ID
            List<Long> robotIds = alertRobotMapper.selectList(Wrappers.<AlertRobot>lambdaQuery()
                            .eq(AlertRobot::getAlertId, id))
                    .stream()
                    .map(AlertRobot::getRobotId)
                    .collect(Collectors.toList());


            if (!CollUtils.isEmpty(robotIds)) {
                Result<List<RobotVO>> robotResult = robotClient.getRobotsByIds(robotIds);
                if (robotResult.success()) {
                    detailVO.setRobots(robotResult.getData());
                } else {
                    detailVO.setRobots(Collections.emptyList());
                }
            } else {
                detailVO.setRobots(Collections.emptyList());
            }
        }

        if (alert.getStatus() == AlertStatus.PROCESSED) {
            detailVO.setDetections(detectionService.getDetectionsByAlertId(alert.getId(), 1, 10)
                    .getList()
                    .stream()
                    .map(detection -> BeanUtils.copyProperties(detection, DetectionVO.class))
                    .collect(Collectors.toList()));
        }

        return detailVO;
    }

    @Override
    public AlertStatisticsVO getAlertStatistics() {
        // 今日开始时间
        LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);

        // 统计今日警情
        int todayCount = Math.toIntExact(lambdaQuery()
                .ge(Alert::getCreatedTime, todayStart)
                .count());

        // 统计处理中的警情
        int processingCount = Math.toIntExact(lambdaQuery()
                .eq(Alert::getStatus, AlertStatus.PROCESSING)
                .count());

        // 统计待处理的警情
        int pendingCount = Math.toIntExact(lambdaQuery()
                .eq(Alert::getStatus, AlertStatus.PENDING)
                .count());

        return AlertStatisticsVO.builder()
                .todayAlertCount(todayCount)
                .processingCount(processingCount)
                .pendingCount(pendingCount)
                .build();
    }

    @Override
    public List<AlertTypeStatVO> getAlertTypeStats() {
        // 获取本月和上月的时间范围
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime thisMonthStart = now.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0);
        LocalDateTime lastMonthStart = thisMonthStart.minusMonths(1);

        // 查询本月和上月的数据
        List<Alert> thisMonthAlerts = alertMapper.selectList(
                Wrappers.<Alert>lambdaQuery()
                        .ge(Alert::getAlertTime, thisMonthStart)
        );

        List<Alert> lastMonthAlerts = alertMapper.selectList(
                Wrappers.<Alert>lambdaQuery()
                        .between(Alert::getAlertTime, lastMonthStart, thisMonthStart)
        );

        // 按类型分组统计
        Map<AlertType, List<Alert>> thisMonthMap = thisMonthAlerts.stream()
                .collect(Collectors.groupingBy(Alert::getAlertType));

        Map<AlertType, List<Alert>> lastMonthMap = lastMonthAlerts.stream()
                .collect(Collectors.groupingBy(Alert::getAlertType));

        // 计算统计指标
        return Arrays.stream(AlertType.values())
                .map(type -> {
                    List<Alert> thisMonthTypeAlerts = thisMonthMap.getOrDefault(type, new ArrayList<>());
                    List<Alert> lastMonthTypeAlerts = lastMonthMap.getOrDefault(type, new ArrayList<>());

                    int thisMonthCount = thisMonthTypeAlerts.size();
                    int lastMonthCount = lastMonthTypeAlerts.size();

                    // 计算平均响应时间，如果 responseTime 为 null，则用 now - createdTime
                    double avgResponse = thisMonthTypeAlerts.stream()
                            .mapToInt(alert -> {
                                Integer responseTime = alert.getResponseTime();
                                if (responseTime != null) {
                                    return responseTime;
                                } else {
                                    // 计算当前时间与创建时间的时间差（单位：分钟）
                                    return (int) ChronoUnit.MINUTES.between(alert.getCreatedTime(), now);
                                }
                            })
                            .average()
                            .orElse(0.0);

                    // 计算环比变化
                    BigDecimal monthOverMonth = lastMonthCount == 0 ?
                            BigDecimal.ZERO :
                            BigDecimal.valueOf(thisMonthCount - lastMonthCount)
                                    .divide(BigDecimal.valueOf(lastMonthCount), 4, RoundingMode.HALF_UP)
                                    .multiply(BigDecimal.valueOf(100));

                    // 计算占比
                    BigDecimal percentage = thisMonthAlerts.isEmpty() ?
                            BigDecimal.ZERO :
                            BigDecimal.valueOf(thisMonthCount)
                                    .divide(BigDecimal.valueOf(thisMonthAlerts.size()), 4, RoundingMode.HALF_UP)
                                    .multiply(BigDecimal.valueOf(100));

                    return AlertTypeStatVO.builder()
                            .alertType(type)
                            .currentMonthCount(thisMonthCount)
                            .lastMonthCount(lastMonthCount)
                            .percentage(percentage)
                            .monthOverMonthChange(monthOverMonth)
                            .avgResponseTime(avgResponse)
                            .build();
                })
                .collect(Collectors.toList());
    }

    @Override
    public AlertTypeDistributionVO getAlertTypeDistribution(String timeRange) {
        // 确定时间范围
        LocalDateTime startTime;
        LocalDateTime endTime = LocalDateTime.now();

        if ("week".equals(timeRange)) {
            startTime = endTime.minusWeeks(1);
        } else {
            startTime = endTime.minusMonths(1);
        }

        // 查询指定时间范围内的警情
        LambdaQueryWrapper<Alert> wrapper = Wrappers.<Alert>lambdaQuery()
                .between(Alert::getAlertTime, startTime, endTime);

        List<Alert> alerts = alertMapper.selectList(wrapper);

        // 按类型分组统计
        Map<AlertType, Long> typeCountMap = alerts.stream()
                .collect(Collectors.groupingBy(Alert::getAlertType, Collectors.counting()));

        // 计算总数
        int total = alerts.size();

        return AlertTypeDistributionVO.builder()
                .distribution(typeCountMap)
                .totalCount(total)
                .build();
    }

    @Override
    public AlertTrendVO getAlertTrend(String alertType) {
        // 获取近6周的起始时间
        LocalDateTime endTime = LocalDateTime.now();
        LocalDateTime startTime = endTime.minusWeeks(6)
                .with(DayOfWeek.MONDAY)  // Start from Monday of that week
                .withHour(0)
                .withMinute(0)
                .withSecond(0)
                .withNano(0);

        // 构建查询条件
        LambdaQueryWrapper<Alert> wrapper = Wrappers.<Alert>lambdaQuery()
                .between(Alert::getAlertTime, startTime, endTime);

        if (alertType != null && !alertType.equals("all")) {
            wrapper.eq(Alert::getAlertType, AlertType.fromValue(alertType));
        }

        List<Alert> alerts = alertMapper.selectList(wrapper);

        // 按周和类型统计
        DateTimeFormatter weekFormatter = DateTimeFormatter.ofPattern("yyyy-ww");
        Map<String, Map<String, Integer>> weeklyStats = alerts.stream()
                .collect(Collectors.groupingBy(
                        alert -> alert.getAlertTime().format(weekFormatter),
                        Collectors.groupingBy(
                                alert -> alert.getAlertType().getValue(),
                                Collectors.collectingAndThen(Collectors.counting(), Long::intValue)
                        )
                ));

        // 构建周列表
        List<String> weeks = new ArrayList<>();
        Map<String, List<Integer>> alertCountByType = new HashMap<>();
        List<Integer> totalCount = new ArrayList<>();

        // 初始化每种警情类型的计数列表
        for (AlertType type : AlertType.values()) {
            alertCountByType.put(type.getValue(), new ArrayList<>());
        }

        // 填充数据
        LocalDateTime current = startTime;
        int weekCount = 0;
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("MM月dd日"); // 格式化为“月日”
        while (weekCount < 6) {  // 确保只获取6周
            String weekKey = current.format(weekFormatter);
            LocalDateTime weekEnd = current.plusDays(6); // 一周的最后一天（星期日）
            String weekRange = current.format(dateFormatter) + " - " + weekEnd.format(dateFormatter);
            weeks.add(weekRange); // 添加日期范围，如“03月03日 - 03月09日”

            Map<String, Integer> weekData = weeklyStats.getOrDefault(weekKey, new HashMap<>());

            int weekTotal = 0;
            for (AlertType type : AlertType.values()) {
                int count = weekData.getOrDefault(type.getValue(), 0);
                alertCountByType.get(type.getValue()).add(count);
                weekTotal += count;
            }

            totalCount.add(weekTotal);
            current = current.plusWeeks(1);
            weekCount++;
        }

        return AlertTrendVO.builder()
                .months(weeks)  // Note: property name is still 'months' but contains week ranges
                .alertCountByType(alertCountByType)
                .totalCount(totalCount)
                .build();
    }

    @Override
    public Integer getTotalAlertCount() {
        return Math.toIntExact(count());
    }

    @Override
    public Double getUrgentAlertPercentage() {
        long totalCount = count();
        if (totalCount == 0) {
            return 0.0;
        }
        long urgentCount = lambdaQuery()
                .eq(Alert::getEmergencyLevel, URGENT)
                .count();
        // 使用BigDecimal控制精度
        BigDecimal percentage = BigDecimal.valueOf(urgentCount)
                .divide(BigDecimal.valueOf(totalCount), 2, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100));
        return percentage.doubleValue();
    }

    @Override
    public String getMostCommonAlertType() {
        // 查找出现次数最多的火灾类型
        return lambdaQuery()
                .select(Alert::getAlertType)
                .groupBy(Alert::getAlertType)
                .orderByDesc(Alert::getAlertType) // 按计数排序
                .last("LIMIT 1")
                .list() // 返回列表
                .stream()
                .findFirst()
                .map(Alert::getAlertType)
                .map(AlertType::getValue) // 如果是枚举
                .orElse(null);
    }

    @Override
    public Double getAverageResponseTime() {
        // 计算平均响应时间，如果 responseTime 为 null，则用 now - createdTime
        // 获取所有警情记录
        List<Alert> alerts = list();
        if (alerts == null || alerts.isEmpty()) {
            return 0.0;
        }

        // 计算总响应时间
        long totalResponseTime = 0;
        LocalDateTime now = LocalDateTime.now();

        for (Alert alert : alerts) {
            if (alert.getResponseTime() != null) {
                // 如果 responseTime 不为空，直接使用
                totalResponseTime += alert.getResponseTime();
            } else {
                // 如果 responseTime 为空，计算 now - createdTime（单位：分钟）
                Duration duration = Duration.between(alert.getCreatedTime(), now);
                totalResponseTime += duration.toMinutes();
            }
        }

        // 计算平均值
        return (double) totalResponseTime / alerts.size();
    }

    @Override
    public AlertStatsTrendVO getAlertStatsTrend() {
        // 计算近7周的起始时间（当前时间往前推6周）
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime startTime = now.minusWeeks(6)
                .withHour(0)
                .withMinute(0)
                .withSecond(0)
                .withNano(0)
                .with(DayOfWeek.MONDAY); // Start from Monday of that week

        // 使用 LambdaQueryWrapper 查询近7周的警情数据
        LambdaQueryWrapper<Alert> queryWrapper = new LambdaQueryWrapper<Alert>()
                .ge(Alert::getCreatedTime, startTime);
        List<Alert> alerts = list(queryWrapper);

        // 如果无数据，返回空结果
        if (alerts == null || alerts.isEmpty()) {
            AlertStatsTrendVO dto = new AlertStatsTrendVO();
            dto.setMonths(createEmptyWeeks(startTime));  // 修改为按周的日期范围
            dto.setAlertCounts(List.of(0L, 0L, 0L, 0L, 0L, 0L, 0L));
            dto.setAvgResponseTimes(List.of(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
            return dto;
        }

        // 按周分组统计
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-ww"); // 使用年-周格式
        Map<String, List<Alert>> alertsByWeek = alerts.stream()
                .collect(Collectors.groupingBy(
                        alert -> alert.getCreatedTime().format(formatter),
                        Collectors.toList()
                ));

        // 初始化7周的结果列表
        List<String> weeks = new ArrayList<>(7);
        List<Long> countData = new ArrayList<>(7);
        List<Double> responseTimeData = new ArrayList<>(7);

        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("MM月dd日"); // 格式化为“月日”
        for (int i = 0; i < 7; i++) {
            LocalDateTime weekStart = startTime.plusWeeks(i);
            LocalDateTime weekEnd = weekStart.plusDays(6); // 一周的最后一天（星期日）
            String weekRange = weekStart.format(dateFormatter) + " - " + weekEnd.format(dateFormatter);
            weeks.add(weekRange); // 添加日期范围，如“03月03日 - 03月09日”

            // 获取该周数据
            String weekKey = weekStart.format(formatter);
            List<Alert> weekAlerts = alertsByWeek.getOrDefault(weekKey, new ArrayList<>());

            // 统计警情数量
            long count = weekAlerts.size();
            countData.add(count);

            // 计算平均响应时间
            if (weekAlerts.isEmpty()) {
                responseTimeData.add(0.0);
            } else {
                double totalResponseTime = weekAlerts.stream()
                        .mapToDouble(alert -> {
                            if (alert.getResponseTime() != null) {
                                return alert.getResponseTime();
                            } else {
                                Duration duration = Duration.between(alert.getCreatedTime(), now);
                                return duration.toMinutes();
                            }
                        })
                        .sum();
                responseTimeData.add(totalResponseTime / weekAlerts.size());
            }
        }

        // 构造返回 DTO
        AlertStatsTrendVO dto = new AlertStatsTrendVO();
        dto.setMonths(weeks);  // 存储日期范围
        dto.setAlertCounts(countData);
        dto.setAvgResponseTimes(responseTimeData);
        return dto;
    }

    // 修改为空数据时的辅助方法
    private List<String> createEmptyWeeks(LocalDateTime startTime) {
        List<String> weeks = new ArrayList<>(7);
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("MM月dd日"); // 格式化为“月日”
        for (int i = 0; i < 7; i++) {
            LocalDateTime weekStart = startTime.plusWeeks(i);
            LocalDateTime weekEnd = weekStart.plusDays(6); // 一周的最后一天（星期日）
            String weekRange = weekStart.format(dateFormatter) + " - " + weekEnd.format(dateFormatter);
            weeks.add(weekRange);
        }
        return weeks;
    }

    @Override
    public List<AlertDashboardVO> getDashboardList() {
        // 获取所有没有处理的警情信息，并按创建时间倒序排序
        List<Alert> alerts = lambdaQuery()
                .eq(Alert::getStatus, AlertStatus.PENDING)
                .orderByDesc(Alert::getCreatedTime)
                .list();

        return alerts.stream()
                .map(alert -> {
                    AlertDashboardVO dto = BeanUtils.copyProperties(alert, AlertDashboardVO.class);
                    dto.setContent(alert.getLocation() + '域' + alert.getIncidentDesc());
                    dto.setTime(alert.getAlertTime());
                    return dto;
                })
                .collect(Collectors.toList());
    }

    // 生成空月份列表
    private List<String> createEmptyMonths(LocalDateTime startTime) {
        List<String> months = new ArrayList<>(6);
        for (int i = 0; i < 6; i++) {
            months.add(startTime.plusMonths(i).getMonthValue() + "月");
        }
        return months;
    }
}
